package core

import (
	"context"
	"fmt"
	"github.com/shirou/gopsutil/cpu"
	"github.com/shirou/gopsutil/host"
	"github.com/shirou/gopsutil/mem"
	"github.com/shirou/gopsutil/process"
	"os"
	"reflect"
	"time"
	"uss-root/utils"
)

type SystemState struct {
	HostId  string  `json:"host_id" influx:"tag"` //主机id
	Pid     int     `json:"pid" influx:"field"`
	MemUsed uint64  `json:"mem_used" influx:"field"`       //系统内存使用量
	CpuUsed float64 `json:"cpu_used" influx:"field"`       //系统cpu使用百分比
	ConnNum int     `json:"connection_num" influx:"field"` //此程序网络连接数量
	Rss     uint64  `json:"rss" influx:"field"`            //此程序内存使用量
	Ts      int64   `json:"ts" influx:"field"`             //时间戳
}

func NewSystemState(duration time.Duration) *SystemState {
	h, _ := host.Info()
	m, _ := mem.VirtualMemory()
	c, _ := cpu.Percent(duration, false)
	p, _ := process.NewProcess(int32(os.Getpid()))
	pn, _ := p.Connections()
	pm, _ := p.MemoryInfo()
	c0 := 0.0
	if len(c) == 1 {
		c0 = c[0]
	}
	return &SystemState{
		HostId:  h.HostID,
		Pid:     os.Getpid(),
		MemUsed: m.Used,
		CpuUsed: c0,
		ConnNum: len(pn),
		Rss:     pm.RSS,
		Ts:      time.Now().Unix(),
	}
}

func GenerateSysStream(ctx context.Context, duration time.Duration) chan *SystemState {
	defer func() {
		if err := recover(); err != nil {
			utils.HandleErr(err.(error))
		}
	}()
	c := make(chan *SystemState)
	tk := time.NewTicker(duration)
	h, _ := host.Info()
	utils.Logger.Info().Str("OS_ID:", h.HostID).Send()
	utils.Logger.Info().Int("PID:", os.Getpid()).Send()
	go func() {
		for {
			select {
			case <-ctx.Done():
				utils.Logger.Info().Msg("GenerateSysStream Done")
				return
			case <-tk.C:
				c <- NewSystemState(duration)
			}
		}
	}()
	return c
}

func (self *SystemState) TagParse() string {
	tagMap := make(map[string]interface{})
	fileMap := make(map[string]interface{})
	t := reflect.TypeOf(self).Elem()
	n := t.NumField()

	v := reflect.ValueOf(self).Elem()
	for i := 0; i < n; i++ {
		f := t.Field(i)
		tag := f.Tag.Get("influx")
		if tag == "tag" {
			tagMap[f.Tag.Get("json")] = v.Field(i).Interface()
		}
		if tag == "field" {
			fileMap[f.Tag.Get("json")] = v.Field(i).Interface()
		}
	}
	tagMsg := ""
	for k, v := range tagMap {
		if tagMsg == "" {
			tagMsg = fmt.Sprintf("%v=%v", k, v)
		} else {
			tagMsg = fmt.Sprintf("%v,%v=%v", tagMsg, k, v)
		}
	}
	fileMsg := ""
	for k, v := range fileMap {
		if fileMsg == "" {
			fileMsg = fmt.Sprintf("%v=%v", k, v)
		} else {
			fileMsg = fmt.Sprintf("%v,%v=%v", fileMsg, k, v)
		}
	}
	msg := fmt.Sprintf("%v %v", tagMsg, fileMsg)
	return msg
}
